package com.getan.boot.module.system.service.persistent;

import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.getan.boot.common.Pagination;
import com.getan.boot.common.enums.EnableStatus;
import com.getan.boot.common.utils.CollectionUtils;
import com.getan.boot.common.utils.Preconditions;
import com.getan.boot.jdbc.customquery.CustomQueryBO;
import com.getan.boot.jdbc.service.GenericService;
import com.getan.boot.module.system.constant.ErrorCode;
import com.getan.boot.module.system.entity.DictEntity;
import com.getan.boot.module.system.entity.DictTypeEntity;
import com.getan.boot.module.system.repository.DictRepository;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Comparator;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * 字典管理
 *
 * @author Bruce.Gong
 * @since 1.0.0-SNAPSHOT
 */
@Slf4j
@RequiredArgsConstructor
@Service
@Transactional(propagation = Propagation.SUPPORTS, rollbackFor = Exception.class)
public class DictService extends GenericService<DictRepository, DictEntity> {

    private final DictTypeService dictTypeService;

    // region 字典类型操作方法

    /**
     * 查询字典类型
     *
     * @param bo 自定义查询
     * @return 分页数据
     */
    public Pagination<DictTypeEntity> searchType(CustomQueryBO bo) {
        return dictTypeService.page(bo);
    }

    /**
     * 根据字典类型，查询字典项
     *
     * @param code 字典类型
     * @return 字典项列表
     */
    public List<DictEntity> listByType(String code, boolean active) {
        List<DictEntity> list = list(Wrappers.<DictEntity>lambdaQuery()
                .eq(DictEntity::getType, code)
                .eq(active, DictEntity::getStatus, EnableStatus.ENABLE.getCode()));
        if (!active && CollectionUtils.isNotEmpty(list)) {
            list.sort(Comparator.comparing(DictEntity::getStatus).thenComparing(DictEntity::getSort));
        }
        return list;
    }

    /**
     * 校验字典类型是否唯一
     *
     * @param entity {id,pid,name}
     */
    public void checkTypeCode(DictTypeEntity entity) {
        Preconditions.check(() -> dictTypeService.exists(Wrappers.<DictTypeEntity>lambdaQuery()
                .eq(DictTypeEntity::getType, entity.getType())), ErrorCode.DICT_TYPE_EXISTS);
    }

    /**
     * 校验字典类型是否存在
     *
     * @param ids 字典类型ID
     */
    public List<DictTypeEntity> checkTypeExists(List<Long> ids) {
        List<DictTypeEntity> dbs = dictTypeService.list(Wrappers.<DictTypeEntity>lambdaQuery()
                .select(DictTypeEntity::getId, DictTypeEntity::getType,
                        DictTypeEntity::getSys, DictTypeEntity::getStatus)
                .in(DictTypeEntity::getId, ids));
        Preconditions.check(() -> dbs.size() != ids.size(), ErrorCode.DICT_TYPE_NOT_EXISTS);
        return dbs;
    }

    /**
     * 校验字典类型是否存在
     *
     * @param id 字典类型ID
     */
    private DictTypeEntity checkTypeExists(Long id) {
        DictTypeEntity db = dictTypeService.getById(id);
        Preconditions.isNull(db, ErrorCode.DICT_TYPE_NOT_EXISTS);
        return db;
    }

    /**
     * 校验字典类型是否存在
     *
     * @param dbs     字典类型
     * @param operate 操作
     */
    private void checkTypeSystem(List<DictTypeEntity> dbs, String operate) {
        List<String> sysCodes = dbs.stream()
                .filter(v -> Boolean.TRUE.equals(v.getSys()))
                .map(DictTypeEntity::getType)
                .collect(Collectors.toList());
        Preconditions.notEmpty(sysCodes, ErrorCode.DICT_TYPE_IS_SYS, sysCodes, operate);
    }


    /**
     * 校验字典是否可修改
     *
     * @param id 字典类型ID
     */
    public DictTypeEntity typeCanUpdate(Long id) {
        DictTypeEntity db = checkTypeExists(id);
        Preconditions.check(() -> EnableStatus.DISABLE.match(db.getStatus()), ErrorCode.DICT_TYPE_DISABLED);
        return db;
    }

    /**
     * 校验字典是否可删除
     *
     * @param ids 字典类型ID
     */
    public List<DictTypeEntity> typeCanDelete(List<Long> ids) {
        List<DictTypeEntity> dbs = checkTypeExists(ids);
        checkTypeSystem(dbs, "删除");
        return dbs;
    }

    /**
     * 校验字典是否可停用
     *
     * @param ids 字典类型ID
     */
    public List<DictTypeEntity> typeCanDisable(List<Long> ids) {
        List<DictTypeEntity> dbs = checkTypeExists(ids);
        checkTypeSystem(dbs, "停用");
        List<String> disableCodes = dbs.stream()
                .filter(v -> EnableStatus.DISABLE.match(v.getStatus()))
                .map(DictTypeEntity::getType)
                .collect(Collectors.toList());
        Preconditions.notEmpty(disableCodes, ErrorCode.DICT_TYPE_IS_DISABLED, disableCodes);
        return dbs;
    }

    /**
     * 校验字典是否可启用
     *
     * @param ids 字典类型ID
     */
    public void typeCanEnable(List<Long> ids) {
        List<DictTypeEntity> dbs = checkTypeExists(ids);
        List<String> enableCodes = dbs.stream()
                .filter(v -> EnableStatus.ENABLE.match(v.getStatus()))
                .map(DictTypeEntity::getType)
                .collect(Collectors.toList());
        Preconditions.notEmpty(enableCodes, ErrorCode.DICT_TYPE_IS_ENABLE, enableCodes);
    }

    /**
     * 新增字典类型
     *
     * @param entity 字典类型
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void insertType(DictTypeEntity entity) {
        entity.setSys(false);
        entity.setStatus(EnableStatus.ENABLE.getCode());
        dictTypeService.insert(entity);
    }

    /**
     * 修改字典类型
     *
     * @param entity 字典类型
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void updateType(DictTypeEntity entity) {
        dictTypeService.update(entity);
    }

    /**
     * 删除字典类型
     *
     * @param entities 字典类型
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void deleteType(List<DictTypeEntity> entities) {
        Map<Long, String> map = entities.stream().collect(Collectors.toMap(DictTypeEntity::getId, DictTypeEntity::getType));
        dictTypeService.deleteBatch(map.keySet());
        delete(Wrappers.<DictEntity>lambdaUpdate()
                .in(DictEntity::getType, map.values()));
    }

    /**
     * 停用字典类型
     *
     * @param entities 字典类型
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void disableType(List<DictTypeEntity> entities) {
        Map<Long, String> map = entities.stream().collect(Collectors.toMap(DictTypeEntity::getId, DictTypeEntity::getType));
        dictTypeService.update(Wrappers.<DictTypeEntity>lambdaUpdate()
                .set(DictTypeEntity::getStatus, EnableStatus.DISABLE.getCode())
                .in(DictTypeEntity::getId, map.keySet())
                .eq(DictTypeEntity::getStatus, EnableStatus.ENABLE.getCode()));
        update(Wrappers.<DictEntity>lambdaUpdate()
                .set(DictEntity::getStatus, EnableStatus.DISABLE.getCode())
                .in(DictEntity::getType, map.values())
                .eq(DictEntity::getStatus, EnableStatus.ENABLE.getCode()));
    }

    /**
     * 停用字典类型
     *
     * @param ids 字典ID
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void enableType(List<Long> ids) {
        dictTypeService.update(Wrappers.<DictTypeEntity>lambdaUpdate()
                .set(DictTypeEntity::getStatus, EnableStatus.ENABLE.getCode())
                .in(DictTypeEntity::getId, ids)
                .eq(DictTypeEntity::getStatus, EnableStatus.DISABLE.getCode()));
    }

    // endregion

    /**
     * 校验字典项编码是否唯一
     *
     * @param entity {type,code}
     */
    public void checkItemCode(DictEntity entity) {
        Preconditions.check(() -> exists(Wrappers.<DictEntity>lambdaQuery()
                .eq(DictEntity::getType, entity.getType())
                .eq(DictEntity::getCode, entity.getCode())), ErrorCode.DICT_CODE_EXISTS);
    }

    /**
     * 校验字典项能否修改
     *
     * @param id 字典项ID
     */
    private void checkActive(Long id) {
        DictEntity db = getById(id);
        Preconditions.isNull(db, ErrorCode.DICT_NOT_EXISTS);
        Preconditions.check(() -> EnableStatus.DISABLE.match(db.getStatus()), ErrorCode.DICT_DISABLED);
    }

    /**
     * 校验字典项能否删除
     *
     * @param ids 配置ID
     */
    private List<DictEntity> checkExists(List<Long> ids) {
        List<DictEntity> dbs = list(Wrappers.<DictEntity>lambdaQuery()
                .select(DictEntity::getId, DictEntity::getCode, DictEntity::getStatus)
                .in(DictEntity::getId, ids));
        Preconditions.check(() -> dbs.size() != ids.size(), ErrorCode.DICT_NOT_EXISTS);
        return dbs;
    }

    /**
     * 检查字典是否停用
     *
     * @param dbs 字典项
     */
    public void checkDisabled(List<DictEntity> dbs) {
        List<String> disableCodes = dbs.stream()
                .filter(v -> EnableStatus.DISABLE.match(v.getStatus()))
                .map(DictEntity::getCode)
                .collect(Collectors.toList());
        Preconditions.notEmpty(disableCodes, ErrorCode.DICT_IS_DISABLED, disableCodes);
    }

    /**
     * 校验字典项能否可修改
     *
     * @param id 配置ID
     */
    public void canUpdate(Long id) {
        checkActive(id);
    }

    /**
     * 校验字典项能否可删除
     *
     * @param ids 配置ID
     */
    public void canDelete(List<Long> ids) {
        checkExists(ids);
    }

    /**
     * 校验字典项能否停用
     *
     * @param ids 配置ID
     */
    public List<DictEntity> canDisable(List<Long> ids) {
        List<DictEntity> dbs = checkExists(ids);
        checkDisabled(dbs);
        return dbs;
    }

    /**
     * 校验字典项能否停用
     *
     * @param ids 配置ID
     */
    public List<DictEntity> canEnable(List<Long> ids) {
        List<DictEntity> dbs = checkExists(ids);
        List<String> disableCodes = dbs.stream()
                .filter(v -> EnableStatus.ENABLE.match(v.getStatus()))
                .map(DictEntity::getCode)
                .collect(Collectors.toList());
        Preconditions.notEmpty(disableCodes, ErrorCode.DICT_IS_ENABLE, disableCodes);
        return dbs;
    }

    /**
     * 停用字典项
     *
     * @param ids 字典项ID
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void disable(List<Long> ids) {
        update(Wrappers.<DictEntity>lambdaUpdate()
                .set(DictEntity::getStatus, EnableStatus.DISABLE.getCode())
                .in(DictEntity::getId, ids)
                .eq(DictEntity::getStatus, EnableStatus.ENABLE.getCode()));
    }

    /**
     * 启用字典项
     *
     * @param ids 字典项ID
     */
    @Transactional(propagation = Propagation.REQUIRED, rollbackFor = Exception.class)
    public void enable(List<Long> ids) {
        update(Wrappers.<DictEntity>lambdaUpdate()
                .set(DictEntity::getStatus, EnableStatus.ENABLE.getCode())
                .in(DictEntity::getId, ids)
                .eq(DictEntity::getStatus, EnableStatus.DISABLE.getCode()));
    }


}
